package com.lmn.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;

@Configuration
public class RestTemplateConfig {

    /**
     * 配置 RestTemplate 并使用连接池
     */
    @Bean
    public RestTemplate restTemplate() {
        // 创建连接池管理器
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();

        // 全局最大连接数
        connectionManager.setMaxTotal(50);
        // 每个路由的最大连接数（路由指域名+端口）
        connectionManager.setDefaultMaxPerRoute(20);

        // 连接配置（超时、存活时间等）
        ConnectionConfig connectionConfig = ConnectionConfig.custom()
                // 连接超时时间
                .setConnectTimeout(Timeout.ofSeconds(10))
                .setSocketTimeout(Timeout.ofSeconds(30))
                .setValidateAfterInactivity(Timeout.ofSeconds(30))  //连接空闲多长时间（单位：毫秒）进行检查
                .setTimeToLive(TimeValue.ofMinutes(5))  // 连接存活时间（空闲时）
                .build();
        connectionManager.setDefaultConnectionConfig(connectionConfig);

        // 请求配置（读取、写入超时等）
        RequestConfig requestConfig = RequestConfig.custom()
                // 读取超时时间
                .setResponseTimeout(Timeout.ofSeconds(10))
                // 允许重定向
                .setRedirectsEnabled(true)
                .build();

        // 创建 HttpClient 实例
        HttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                // 定期清理无效连接
                .evictIdleConnections(TimeValue.ofMinutes(1))
                // 关闭连接时是否关闭底层socket
                .evictExpiredConnections()
                .build();

        // 创建请求工厂并设置 HttpClient
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

        // 设置连接池关闭时的等待时间
        requestFactory.setConnectionRequestTimeout(5000);

        // 构建 RestTemplate
        RestTemplate restTemplate = new RestTemplate(requestFactory);


        // 配置消息转换器
        List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
        converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
        MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        jacksonConverter.setObjectMapper(objectMapper);
        converters.add(jacksonConverter);

        // 添加拦截器
        restTemplate.setInterceptors(Arrays.asList(
                new LoggingRequestInterceptor(), // 自定义日志拦截器
                (request, body, execution) -> {
                    request.getHeaders().add("Authorization", "Bearer token");
                    return execution.execute(request, body);
                }
        ));

        // 配置错误处理器
        restTemplate.setErrorHandler(new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse response) throws IOException {
                return response.getStatusCode().isError();
            }

            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                // 自定义错误处理逻辑
                throw new RuntimeException(response.getStatusCode() + " " + response.getStatusText());
            }
        });


        return restTemplate;
    }
}
